const fs = require('fs')
const EventEmit = require('events')
const { Queue } = require('../linkList/index')

class WriteStream extends EventEmit {
    constructor(path, options = {}) {
        super()
        this.path = path
        this.flags = options.flags || 'w';
        this.encoding = options.encoding || 'utf-8';
        this.start = options.start || 0
        this.highWaterMark = options.highWaterMark || 16 * 1024
        this.open()
        // len 记录流的总数量   写入完成后递减  
        this.len = 0
        this.offset = options.start // 每次写入的偏移量
        this.cache = new Queue   // 缓存写入操作.
        // this.cache = []
        this.needDrain = false // 是否需要触发drain
        this.writing = false  // 是否正在写入
    }


    destroy(err) {
        if (err) {
            this.emit('error', err)
        }
        if (this.autoClose) {
            this.emit('close')
        }
    }

    open() {
        fs.open(this.path, this.flags, (err, fd) => {
            if (err) {
                return this.destroy(err)
            }
            this.fd = fd
            this.emit('open', fd)
        })
    }

    clearBuffer() { // 吸入成功时 清空缓存区
        let obj = this.cache.peek()
        // let obj = this.cache.shift()
        if (obj) {
            const { chunk, encoding, cb } = obj.element
            this._write(chunk, encoding, cb)
        } else {
            this.writing = false
            if (this.needDrain) {
                this.needDrain = false
                this.emit('drain')
            }
        }
    }

    write(chunk, encoding = null, cb = () => { }) {

        chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) //buffer| string
        this.len += chunk.length
        //  需要写入的数据是否高于水位线， 决定是否需要触发drain  即是否需要写入缓存区
        this.needDrain = this.len >= this.highWaterMark;
        let oldCb = cb

        cb = () => {
            oldCb()
            this.clearBuffer()
        }
        if (this.writing) { // 正在写入时  先写进缓存
            this.cache.add({
                // this.cache.push({
                chunk, encoding, cb
            })
        } else { //  可以直接写入文件
            this.writing = true
            this._write(chunk, encoding, cb)
        }
        return !this.needDrain
    }
    _write(chunk, encoding, cb) {
        if (typeof this.fd !== 'number') {
            return this.once('open', () => this._write(chunk, encoding, cb))
        }

        fs.write(this.fd, chunk, 0, chunk.length, this.offset, (err, written) => {
            this.offset += written
            this.len -= written
            cb()
        })
    }
    end(chunk, encoding = null, cb = () => { }) {
        chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk) //buffer| string
        let oldCb = cb
        cb = () => {
            oldCb()
            this.destroy()
        }
        this._write(chunk, encoding, cb)
    }

}

module.exports = WriteStream